/*
 *@description:甘特图公共组件
 *@author: liuchenguang
 *@date: 2021-12-18
 *@version: V1.0.0
 使用方式：<div class="gantt" ref="gantt" :style="{ height: '600px' }"></div>
 选填数据：
 data:
  addGantt:甘特图配置，业务相关性较强的配置在addInitEvent中书写
 methods:
  addInitEvent: 添加初始化操作
*/
import { gantt } from 'processit-dhtmlx-gantt'
import 'processit-dhtmlx-gantt/codebase/dhtmlxgantt.css'

/** 组件定义 */
export const mixin_gantt = {
  data() {
    return {
      // 基础配置
      baseGantt: {
        config: {
          select_task: false, // 任务是否可以点击选中
          fit_tasks: true, // 当task的长度改变时，自动调整图表坐标轴区间用于适配task的长度
          smart_scales: true, // 仅仅渲染在屏幕可见的那部分时间轴。在处理时间轴非常长的时候，可以提升性能
          smart_rendering: true, // 按需渲染, 仅仅渲染在屏幕可见的那部分任务和依赖线。这个在显示大量的任务时，性能比较高
          date_format: '%Y-%m-%d', // 日期格式
          min_column_width: 30, // 调整单位时间刻度的宽度
          // 时间刻度配置
          scales: [{ unit: 'year', step: 1, format: '%Y' }, { unit: 'month', step: 2, format: '%Y-%m' }, { unit: 'day', step: 1, format: '%d' }],
          // 任务树配置
          columns: [{ name: 'text', label: '名称', width: 250, tree: true }, { name: 'start_date', label: '开始时间', width: 100 }, { name: 'end_date', label: '结束时间', width: 100 }]
        },
        templates: {
          task_class: (start, end, task) => 'tl_gantt_task'
        }
      },
      // 其余的甘特图配置，业务相关性较强的配置请放在Methods中书写
      addGantt: {},
      dragMarkerDate: new Date(), // dragmarker默认时间点
      markerLeft: '0px', // dragmarker距离左边距离
      ganttObserver: {}, // ganttObserver监听对象
      markerId: '',
      markerCss: 'dragMarkerDefault', // dragmarker默认classname(注：保持这个class是dragmarker唯一使用)
      isFold: true // 甘特图当前收起状态
    }
  },
  props: {
    // 组件名称
    ganttName: {
      type: String,
      default: 'gantt'
    },
    // 是否开启鼠标移上任务条弹出提示语
    isOpenTooltip: {
      type: Boolean,
      default: false
    },
    // 是否显示拖拽标识
    isShowDragMarker: {
      type: Boolean,
      default: false
    }
  },
  methods: {
    /** 初始化甘特图 */
    initGantt(data) {
      gantt.clearAll()
      gantt.i18n.setLocale('cn') // 设置为中文
      Object.keys(gantt).forEach((key) => {
        if (this.baseGantt[key] || this.addGantt[key]) {
          gantt[key] = { ...gantt[key], ...this.baseGantt[key], ...this.addGantt[key] }
        }
      })
      gantt.config.layout = {
        css: "gantt_container",
        rows: [
          {
            cols: [
              { view: "grid", id: "grid", scrollX: "scrollHor", scrollY: "scrollVer" },
              { resizer: true, width: 1 },
              { view: "timeline", id: "timeline", scrollX: "scrollHor", scrollY: "scrollVer" },
              { view: "scrollbar", scroll: "y", id: "scrollVer" }
            ]
          },
          { view: "scrollbar", scroll: "x", id: "scrollHor", height: 20 }
        ]
      }
      this.addInitEvent()
      // 添加dragmarker
      if (this.isShowDragMarker) {
        this.addDragMarker()
      }
      // 添加提示
      if (this.isOpenTooltip) {
        this.openTooltip()
      }
      this.toGanttObserver()
      gantt.init(this.$refs[this.ganttName])
      gantt.parse(data)
    },
    /** 添加初始化操作 **/
    addInitEvent() {
    },
    /** 甘特图DOM监听**/
    toGanttObserver() {
      let that = this
      this.ganttObserver = new MutationObserver(() => {
        let dragEl = document.getElementsByClassName(that.markerCss)[0]
        if (dragEl) {
          this.throttle(this.dragMarker(), 10)
        }
        let moreCol = document.getElementsByClassName("el-dropdown")
        if (moreCol) {
          for (let i = 0; i < moreCol.length; i++) {
            moreCol[i].addEventListener("mousemove", (event) => {
              event.stopPropagation()
              gantt.ext.tooltips.tooltip.hide()
            })
            moreCol[i].addEventListener("click", (event) => {
              event.stopPropagation()
              gantt.ext.tooltips.tooltip.hide()
            })
          }
        }
      })
      this.ganttObserver.observe(this.$refs[this.ganttName], { childList: true, subtree: true })
    },
    /** dragMarker拖拽方法 **/
    dragMarker() {
      let that = this
      let marker = document.getElementsByClassName(that.markerCss)[0]
      marker.addEventListener("mousedown", function(clickEvent) {
        let markerLeft = parseInt(marker.style.left)
        let startLeft = clickEvent.clientX
        let maxX = document.getElementsByClassName("gantt_data_area")[0].offsetWidth
        document.onmousemove = function(event) {
          event = event || window.event
          let subtract = startLeft - markerLeft
          let left = event.clientX - subtract
          if (left < 7) {
            left = 7
          } else if (left > maxX) {
            left = maxX - 5
          }
          that.markerLeft = left + "px"
          marker.style.left = left + "px"
          document.onmouseup = function() {
            document.onmousemove = null
            document.onmouseup = null
            that.setDragDateByPos()
          }
        }
      })
    },
    /** 增加拖拽标志 **/
    addDragMarker() {
      // 增加marker
      gantt.plugins({
        marker: true
      })
      this.markerId = gantt.addMarker({
        start_date: this.dragMarkerDate,
        css: this.markerCss
      })
    },
    /** 根据拖拽位置获取时间 **/
    setDragDateByPos() {
      let dragCurrDate = gantt.dateFromPos(parseInt(this.markerLeft))
      this.$emit('refreshDragDate', dragCurrDate)
      this.dragMarkerDate = dragCurrDate
      gantt.getMarker(this.markerId).start_date = this.dragMarkerDate
      gantt.updateMarker(this.markerId)
    },
    /** 根据时间设置dragmarker位置 **/
    setDragPositionByDate() {
      this.$nextTick(() => {
        gantt.getMarker(this.markerId).start_date = this.dragMarkerDate
        gantt.updateMarker(this.markerId)
        gantt.showDate(this.dragMarkerDate)
      })
    },
    /** 防抖节流公用方法 **/
    throttle(func, wait) {
      let context
      let args
      let previous = 0
      return function() {
        let now = +new Date()
        context = this
        args = arguments
        if (now - previous > wait) {
          func.apply(context, args)
          previous = now
        }
      }
    },
    /** 打开提示功能 **/
    openTooltip() {
      // 打开提示功能
      gantt.plugins({ tooltip: true })
      // 提示内容
      gantt.templates.tooltip_text = (start, end, task) => {
        const tooltipText = `<b>名称：</b>${task.text}`
        const planStartDateStr = `<br/><b>计划开始日期:</b>${task.start_date}`
        const planEndDateStr = `<br/><b>计划结束日期:</b>${task.end_date}`
        return `${tooltipText}
            ${planStartDateStr}
            ${planEndDateStr}`
      }
    },
    /** 隐藏tooltip **/
    hideGanttTooltip() {
      if (this.isOpenTooltip) {
        setTimeout(() => {
          gantt.ext.tooltips.tooltip.hide()
        }, 500)
      }
    },
    /** 全部展开，全部折叠 */
    unfold() {
      this.isFold = !this.isFold
      if (this.isFold) {
        this.taskData.data.forEach((task) => {
          task.$open = false
        })
      } else {
        this.taskData.data.forEach((task) => {
          task.$open = true
        })
      }
      gantt.init(this.$refs[this.ganttName])
      this.$emit('refreshFold', this.isFold)
    }
  },
  destroyed() {
    this.ganttObserver.disconnect()
  }
}
